﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tedds_Tool;
using System.IO;
using RulesBase.Model;
using Tedds_Tool.RulesBase;
using Tedds_Tool.Compilers.CSharp;
using Tedds_Tool.Automatables;
using System.Windows.Threading;
using LEET.Application;
using System.Diagnostics;
using LEET.StaticAnalisys;
using StaticAnalisys.Visitors;
using LEET.StaticAnalisys.Visitors;
using LEET.Application.Compilers.LEET;
using LEET.LEETCommon.Model;
using LEET.Utilities;


namespace GUI
{
    public class Facade
    {
        private Compiler c;
        private CS_Compiler cs_comp;
        private IScriptFinder finder;
        private IInstructionFactory Factory;
        internal int lines;
        
        public Facade(Compiler comp, CS_Compiler cs_comp, IInstructionFactory fac, IScriptFinder finder)
        {
            Factory = fac;
            c = comp;
            this.cs_comp = cs_comp;
            this.finder = finder;
        }

        public void CompileAsTest(string scriptName)
        {
            Compile(scriptName, new AcceptanceTestConfig());
        }

        public void CompileAsDemo(string scriptName)
        {
            Compile(scriptName, new DemoConfig());
        }

        private void Compile(string scriptName, ICompilerConfig topconfig)
        {
            IDictionary<String,String> cSharp = DeepCompile(scriptName, topconfig);
            foreach(String name in cSharp.Keys)
            {
                using (TextWriter writer = finder.WriteTestClass(name))
                {
                    writer.Write(cSharp[name]);
                }
            }
        }

        public LEETTestResult RunScript(string scriptName)
        {
            return RunAs(scriptName, new AcceptanceTestConfig());
        }

        public LEETTestResult RunDemo(string scriptName)
        {
            return RunAs(scriptName, new DemoConfig());
        }

        private LEETTestResult RunAs(string scriptName, ICompilerConfig topconfig)
        {
            IDictionary<String,String> cSharp = DeepCompile(scriptName, topconfig);
            return Run(scriptName, cSharp.Values);
        }

        private IDictionary<String, String> DeepCompile(String scriptName, ICompilerConfig topConfig)
        {
            IDictionary<String, String> ret = new Dictionary<String, String>();

            CompileableEntityCollector compilables = new CompileableEntityCollector();
            CompositeVisitor cvisitor = new CompositeVisitor();
            cvisitor.Add(new InfiniteRecursionDetection());
            cvisitor.Add(compilables);

            TreeWalker tw = new TreeWalker(Factory, finder);
            tw.Traverse(scriptName, cvisitor);

            using (TextReader reader = finder.FindTestScript(scriptName))
            {
                ret.Add(scriptName, c.Compile(new Script(scriptName, Helpers.ReadAllLines(reader)), topConfig));
            }

            foreach (string name in compilables.Tests)
            {
                using (TextReader reader = finder.FindTestScript(name))
                {
                    ret.Add(name, c.Compile(new Script(name, Helpers.ReadAllLines(reader))));
                }
            }

            foreach (string name in compilables.Rules)
            {
                IRule rule = Rule.Load(name, Factory, finder);
                ret.Add(name, c.Compile(rule).ToString());
            }
            return ret;
        }

        

        private LEETTestResult Run(String mainClass, IEnumerable<String> classFiles)
        {
            ICsCompilerResult ret = cs_comp.Compile(mainClass, classFiles.ToArray());
            if( ret.HasErrors )
            {
                throw new Exception(ret.ToString());
            }
            
            Process process = ret.RunExecutable();
            process.Start();
            process.WaitForExit();

            string stdmsg = process.StandardOutput.ReadToEnd();
            string errmsg = process.StandardError.ReadToEnd();

            return new LEETTestResult(stdmsg, errmsg);
        }

        internal void SaveScript(string scriptName, IEnumerable<String> instructions)
        {
            if (instructions.Count<String>() != 0)
            {
                using (TextWriter sw = finder.CreateTestScript(scriptName))
                {
                    foreach (String o in instructions)
                    {
                        sw.WriteLine(o);
                    }
                }
            }
        }

        internal IEnumerable<string> LoadScript(string scriptName)
        {
            IList<String> ret = new List<String>();
            using (TextReader sr = finder.FindTestScript(scriptName))
            {
                string line;
                while ((line = sr.ReadLine()) != null)
                {
                    if (line != null && line.Trim() != "")
                    {
                        ret.Add(line);
                    }
                }
                lines = ret.Count;
            }
            return ret;
        }
    }
}

